/**
 * 流程建模转换方法
*/

import objtree from '../assets/model-plugin/objtree'
import { getRandomVal, replaceVar } from './util'

// 获取对象中key的个数
function getKeysCount (obj = {}) {
  // eslint-disable-next-line
  let incomingKeysCount = 0, outcomingKeysCount = 0;
  if (obj['bpmn2:incoming']) {
    incomingKeysCount = typeof obj['bpmn2:incoming'] === 'string' ? 1 : obj['bpmn2:incoming'].length
  }
  if (obj['bpmn2:outgoing']) {
    outcomingKeysCount = typeof obj['bpmn2:outgoing'] === 'string' ? 1 : obj['bpmn2:outgoing'].length
  }
  // 表示 ⽹网关有任意个输⼊入和输出流 (可以先尝试⽤用这个值作为默认值)
  let gatewayDirectionStr = 'Unspecified'
  if (incomingKeysCount > 1 && outcomingKeysCount === 1) {
    // 表示 ⽹网关有多个输⼊入，但是必须有⼀一个输出流
    gatewayDirectionStr = 'Converging'
  } else if (incomingKeysCount === 1 && outcomingKeysCount > 1) {
    // 表示 ⽹网关有⼀一个输⼊入，但是必须有多个输出流
    gatewayDirectionStr = 'Diverging'
  } else if (incomingKeysCount > 1 && outcomingKeysCount > 1) {
    // 表示⽹网关有多个输⼊入和多个输出
    gatewayDirectionStr = 'Mixed'
  }
  obj['-gatewayDirection'] = gatewayDirectionStr
}

// 对sequenceFlow进行转换
function sequenceFlowTransform (element, _this) {
  const sourceRefValue = element['-sourceRef']
  if (sourceRefValue && (sourceRefValue.includes('ParallelGateway') || sourceRefValue.includes('ExclusiveGateway'))) {
    // 说明是网关的顺序流
    if (element['bpmn2:conditionExpression']) {
      const conditionExpressionObj = element['bpmn2:conditionExpression']
      if (!conditionExpressionObj['#text']) {
        _this.bool = false
        _this.$Message.error('变量表达式的值不能为空')
        return
      }
      conditionExpressionObj['-id'] = getRandomVal()
      conditionExpressionObj['-language'] = 'http://www.mvel.org/2.0'
      // 替换表达式中的变量，转换为map.get('var')>10形式
      const afterExpress = replaceVar(conditionExpressionObj['#text'])
      // 修改源文件的index.js的代码replace（注释掉的就是）,这里是添加文案
      conditionExpressionObj['#text'] = `<![CDATA[${afterExpress}]]>`
    } else {
      _this.bool = false
      _this.$Message.error('网关节点变量表达式的值不能为空')
    }
  }
}

function getStorageData (camundaType) {
  // 获取storage的值，判断camundaType是否存在
  if (!camundaType) {
    return false
  }
  const { pathname } = location
  const implementationObj = JSON.parse(sessionStorage.getItem('DS_RESOURCE'))
  const implementationArr = (implementationObj[pathname] || {}).ruleList || []
  const isExist = implementationArr.some(ele => ele.value === camundaType)
  return isExist
}

// 对创建规则任务进行转换
function businessTransform (businessRuleTaskObj, xmlJson, _this) {
  if (!businessRuleTaskObj['-name']) {
    _this.bool = false
    _this.$Message.error('任务规则名称不能为空')
    return
  }
  const isCamundaTypeExist = getStorageData(businessRuleTaskObj['-camunda:type'])
  if (!isCamundaTypeExist) {
    _this.bool = false
    _this.$Message.error('任务规则类型不能为空')
    return
  }
  businessRuleTaskObj['-drools:ruleFlowGroup'] = businessRuleTaskObj['-camunda:type']
  const taskId = businessRuleTaskObj['-id']
  const inputOutputName = `${getRandomVal()}_inputOutputName`
  // 输入输出结构
  businessRuleTaskObj['bpmn2:ioSpecification'] = {
    '-id': getRandomVal(),
    'bpmn2:dataInput': {
      '-id': `${taskId}_mpInputX`,
      '-drools:dtype': 'java.util.Map',
      '-itemSubjectRef': `_${taskId}_mpInputXItem`,
      '-name': inputOutputName
    },
    'bpmn2:dataOutput': {
      '-id': `${taskId}_mpOutputX`,
      '-drools:dtype': 'java.util.Map',
      '-itemSubjectRef': `_${taskId}_mpOutputXItem`,
      '-name': inputOutputName
    },
    'bpmn2:inputSet': {
      '-id': getRandomVal(),
      'bpmn2:dataInputRefs': `${taskId}_mpInputX`
    },
    'bpmn2:outputSet': {
      '-id': getRandomVal(),
      'bpmn2:dataOutputRefs': `${taskId}_mpOutputX`
    }
  }
  xmlJson['bpmn2:definitions'][`bpmn2:itemDefinition__${taskId}_mpInputXItem__itemDefinition`] = {
    '-id': `_${taskId}_mpInputXItem`,
    '-structureRef': 'java.util.Map'
  }
  xmlJson['bpmn2:definitions'][`bpmn2:itemDefinition__${taskId}_mpOutputXItem__itemDefinition`] = {
    '-id': `_${taskId}_mpOutputXItem`,
    '-structureRef': 'java.util.Map'
  }
  businessRuleTaskObj['bpmn2:dataInputAssociation'] = {
    '-id': getRandomVal(),
    'bpmn2:sourceRef': 'processVariable',
    'bpmn2:targetRef': `${taskId}_mpInputX`
  }
  businessRuleTaskObj['bpmn2:dataOutputAssociation'] = {
    '-id': getRandomVal(),
    'bpmn2:sourceRef': `${taskId}_mpOutputX`,
    'bpmn2:targetRef': 'processVariable'
  }
}

// 对xml格式的节点顺序进行调整，将<bpmn2:itemDefinitionxxx拼接到字符串的开头
function itemDefinitionStrToHeader (xmlStr) {
  const itemDefinitionStartIndex = xmlStr.indexOf('<bpmn2:itemDefinition')
  const definitionsEndIndex = xmlStr.lastIndexOf('</bpmn2:definitions>')
  const processIndex = xmlStr.indexOf('<bpmn2:process')
  const headerStr = xmlStr.slice(0, processIndex)
  const processStr = xmlStr.slice(processIndex, itemDefinitionStartIndex)
  const processTag = processStr.match(/<bpmn2:process.*?drools:adHoc="false">/)
  const propertyStr = processStr.match(/<bpmn2:property id="processVariable" itemSubjectRef="_mapItem" name="processVariable" \/>/)
  const restProcessStr = processStr.replace(/<bpmn2:process.*?drools:adHoc="false">/, '').replace(/<bpmn2:property id="processVariable" itemSubjectRef="_mapItem" name="processVariable" \/>/, '')
  const itemDefinitionStr = xmlStr.slice(itemDefinitionStartIndex, definitionsEndIndex)
  const combineStr = headerStr + itemDefinitionStr + processTag + propertyStr + restProcessStr + '</bpmn2:definitions>'
  return combineStr
}

// 对json进行循环
function loopJson (object, xmlJson, _this) {
  for (const key in object) {
    if (key === 'bpmn2:exclusiveGateway') {
      // 互斥网关类型
      const exclusiveGatewayArr = object[key]
      if (exclusiveGatewayArr instanceof Array) {
        exclusiveGatewayArr.forEach(exclusiveGatewayObj => {
          getKeysCount(exclusiveGatewayObj)
        })
      } else {
        getKeysCount(object[key])
      }
    } else if (key === 'bpmn2:parallelGateway') {
      // 并行网关类型
      const parallelGatewayArr = object[key]
      if (parallelGatewayArr instanceof Array) {
        parallelGatewayArr.forEach(parallelGatewayObj => {
          getKeysCount(parallelGatewayObj)
        })
      } else {
        getKeysCount(object[key])
      }
    } else if (key === 'bpmn2:sequenceFlow') {
      // 顺序流类型
      const sequenceFlowArr = object[key]
      if (sequenceFlowArr instanceof Array) {
        // 这里使用every代替for循环的break的效果,这样可以只弹出一个message提示
        sequenceFlowArr.forEach(sequenceFlowObj => {
          if (_this.bool) {
            sequenceFlowTransform(sequenceFlowObj, _this)
          }
        })
      } else {
        // 对象类型
        sequenceFlowTransform(object[key], _this)
      }
    } else if (key === 'bpmn2:businessRuleTask') {
      // 规则任务类型
      const businessRuleTaskArr = object[key]
      if (businessRuleTaskArr instanceof Array) {
        businessRuleTaskArr.forEach(businessRuleTaskObj => {
          if (_this.bool) {
            businessTransform(businessRuleTaskObj, xmlJson, _this)
          }
        })
      } else {
        businessTransform(object[key], xmlJson, _this)
      }
    }
  }
}

export const transferData = (xml, _this) => {
  _this.bool = true
  // 转换为json解构
  // eslint-disable-next-line
  const xotree = new objtree()
  const xmlJson = xotree.parseXML(xml)
  for (const key in xmlJson) {
    xmlJson[key]['-xmlns:drools'] = 'http://www.jboss.org/drools'
    const processObj = xmlJson[key]['bpmn2:process']
    const propertyRandomVal = getRandomVal()
    if (processObj) {
      // process
      processObj['-drools:packageName'] = `com.myspace.${_this.processName}`
      processObj['-drools:version'] = '1.0'
      processObj['-drools:adHoc'] = false
      // property和bpmn2:itemDefinition的映射
      processObj['bpmn2:property'] = {
        '-id': 'processVariable',
        '-itemSubjectRef': '_mapItem',
        '-name': 'processVariable'
      }
      xmlJson['bpmn2:definitions'][`bpmn2:itemDefinition__${propertyRandomVal}__itemDefinition`] = {
        '-id': '_mapItem',
        '-structureRef': 'java.util.Map'
      }
      loopJson(processObj, xmlJson, _this)
    }
  }
  // 转换为xmlStr解构
  let xmlStr = xotree.writeXML(xmlJson)
  xmlStr = xmlStr.replace(/bpmn2:itemDefinition__.*?__itemDefinition/mg, 'bpmn2:itemDefinition')
  const finalStr = itemDefinitionStrToHeader(xmlStr)
  return {
    finalStr,
    bool: _this.bool
  }
}
